
`include "common_header.verilog"

//  *************************************************************************
//  File : rx_mld_rst_cntrl_40g.vhd
//  *************************************************************************
//  This program is controlled by a written license agreement.
//  Unauthorized reproduction or use is expressly prohibited.
//  Copyright (c) 2008 MorethanIP
//  Muenchner Strasse 199, 85757 Karlsfeld, Germany
//  info@morethanip.com
//  http://www.morethanip.com
//  *************************************************************************
//  Designed by : Denis Poverennyy
//  info@morethanip.com
//  *************************************************************************
//  Description : RX MLD Reset Controller collects all signals that
//  are causing software reset. Generated general mld_rst stays high until
//  feedback from all serdes domains received (mld_rst_done[11:0])
//  Version     : $Id: rx_mld_rst_cntrl_40g.v,v 1.4 2015/05/12 21:12:43 dk Exp $
//  *************************************************************************

module rx_mld_rst_cntrl_40g (

   reset_rxclk,
   cgmii_rxclk,
   sw_reset,
   desk_buf_full,
   align_lost,
   block_lock,
   mld_rst_done,
   mld_rst);

input   reset_rxclk;            //  async active high reset
input   cgmii_rxclk;            //  cgmii clock
input   sw_reset;               //  software reset from the Registers
input   [3:0] desk_buf_full;    //  if any bit set, receive should be reset
input   align_lost;             //  at least for one lane Alignment was lost
input   [3:0] block_lock;       //  block lock status per lane
input   [3:0] mld_rst_done;     //  feedback signal from each lane.
output   mld_rst; 

reg     mld_rst; 
wire    desk_buf_full_comb;     //  oring all full flags
reg     desk_buf_full_comb_r;   //  oring all full flags (clock delayed)
reg     desk_buf_full_comb_pulse; //  oring all full flags (pulse)                
wire    block_lock_comb;        //  anding all block locks
reg     block_lock_comb_r;      //  anding all block locks (clock delayed)
reg     block_lock_lost_pulse;  //  anding all block locks (pulse)  
reg     sw_reset_r;             //  sw reset (clock delayed)
reg     sw_reset_pulse;         //  sw reset (pulse) 
reg     align_lost_r;           //  alignment lost (clock delayed)
reg     align_lost_pulse;       //  alignment lost (pulse)        
reg     [3:0] mld_rst_done_long;//  level signal to track reset done from each lane
reg     mld_rst_done_comb;      //  if set all reset_done signals received
reg     mld_rst_done_comb_r;    //  if set all reset_done signals received
reg     mld_rst_done_comb_pulse; //  if set all reset_done signals received

assign desk_buf_full_comb = desk_buf_full[0] | desk_buf_full[1] | desk_buf_full[2] | desk_buf_full[3]; 

assign block_lock_comb = block_lock[0] & block_lock[1] & block_lock[2] & block_lock[3]; 

always @(posedge cgmii_rxclk or posedge reset_rxclk)
   begin : process_1
   if (reset_rxclk == 1'b 1)
      begin
      mld_rst_done_long <= {4{1'b 0}};	
      mld_rst_done_comb <= 1'b 0;
      end
   else
      begin
      if (mld_rst_done_comb_pulse == 1'b 1)
         begin
         mld_rst_done_long <= {4{1'b 0}};	
         end
      else
         begin
         if (mld_rst_done[0] == 1'b 1)
            begin
            mld_rst_done_long[0] <= 1'b 1;	
            end
         if (mld_rst_done[1] == 1'b 1)
            begin
            mld_rst_done_long[1] <= 1'b 1;	
            end
         if (mld_rst_done[2] == 1'b 1)
            begin
            mld_rst_done_long[2] <= 1'b 1;	
            end
         if (mld_rst_done[3] == 1'b 1)
            begin
            mld_rst_done_long[3] <= 1'b 1;	
            end
         end
      mld_rst_done_comb <= mld_rst_done_long[0] & mld_rst_done_long[1] & mld_rst_done_long[2] & mld_rst_done_long[3];	
      end
   end


//  Pulses generation

always @(posedge cgmii_rxclk or posedge reset_rxclk)
   begin : process_2
   if (reset_rxclk == 1'b 1)
      begin
      desk_buf_full_comb_r <= 1'b 0;	
      block_lock_comb_r <= 1'b 0;	
      sw_reset_r <= 1'b 0;	
      align_lost_r <= 1'b 0;	
      desk_buf_full_comb_pulse <= 1'b 0;	
      sw_reset_pulse <= 1'b 0;	
      align_lost_pulse <= 1'b 0;	
      block_lock_lost_pulse <= 1'b 0;	
      mld_rst_done_comb_r <= 1'b 0;	
      mld_rst_done_comb_pulse <= 1'b 0;
      end
   else
      begin
      desk_buf_full_comb_r <= desk_buf_full_comb;	
      block_lock_comb_r <= block_lock_comb;	
      sw_reset_r <= sw_reset;	
      align_lost_r <= align_lost;
      mld_rst_done_comb_r <= mld_rst_done_comb;	
      desk_buf_full_comb_pulse <= desk_buf_full_comb & ~desk_buf_full_comb_r;	
      block_lock_lost_pulse <= ~block_lock_comb & block_lock_comb_r;	
      sw_reset_pulse <= sw_reset & ~sw_reset_r;	
      align_lost_pulse <= align_lost & ~align_lost_r & ~mld_rst_done_comb;	        // avoid 2nd reset toggle if sequence is already done from a previous event	
      mld_rst_done_comb_pulse <= mld_rst_done_comb & ~mld_rst_done_comb_r;	
      end
   end

always @(posedge cgmii_rxclk or posedge reset_rxclk)
   begin : process_3
   if (reset_rxclk == 1'b 1)
      begin
      mld_rst <= 1'b 0;	
      end
   else
      begin
      if (mld_rst_done_comb_pulse == 1'b 1)
         begin
         mld_rst <= 1'b 0;	//  to prevent permanent reset
         end
      else if (sw_reset_pulse == 1'b 1 | align_lost_pulse == 1'b 1 | 
               desk_buf_full_comb_pulse == 1'b 1 | block_lock_lost_pulse == 1'b 1 )
               
         begin
         mld_rst <= 1'b 1;	
         end
      end
   end


endmodule // module rx_mld_rst_cntrl_40g

